#include "calc.h"
#include <cctype>
#include <fstream>
#include <cstring>

using namespace std;


calc::calc() {
	try {
		sourceStr = "";
		result_d = 0.0;
		convstr = "";
		history = "";
		eventLog = "";
		setRepMap();
		outLog("calc built!");
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}



calc::calc(const string&str) {
	try {
		sourceStr = str;
		result_d = 0.0;
		convstr = "";
		history = "";
		eventLog = "";
		setRepMap();
		outLog("calc built!");
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}

void calc::input(istream &ins /* = cin */){
	try {
		if (!ins) {
			throw sfError(ISTREAM_ERROR, "istream error");
		}
		getline(ins, sourceStr);
		result_d =0.0;
		convstr = "";
		outLog("input :"+sourceStr);
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}

void calc::input(const string&srcStr) {
	try {
		if (srcStr.empty()) {
			throw sfError(BLANK_STR, "blank string");
		}
		sourceStr = srcStr;
		result_d = 0.0;
		convstr = "";
		outLog("input :" + sourceStr);
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}



void calc::output(long double &rst) {
	try {
		rst = result_d;
		outLog("output to long double!");
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}

void calc::output(ostream &ous /* =cout */ ) {
	try {
		ous << convstr << flush;
		outLog("output to ostream!");
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}

void calc::output(string &str) {
	try {
		str = convstr;
		outLog("output to string!");
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


void calc::runIt() {
	try {
		outLog("analyze ...");
		if (!judgeCmd()) {
			outLog("start calc ...");
			doit();
		}
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


void calc::outHistory(string &str) {
	try {
		str = history;
		outLog("output history to string!");
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


void calc::outEveLog(string &str) {
	try {
		str = eventLog;
		outLog("output event log to string!");
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


void calc::outHistory(ostream &ous /* =cout */) {
	try {
		outLog("output history to ostream!");
		ous << history << flush;
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


void calc::outEveLog(ostream &ous /* =cout */) {
	try {
		outLog("output event log to ostream!");
		ous << eventLog << flush;
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


bool calc::setMap(string key, string value) {
	try {
		if (key.empty() || value.empty()) {
			return false;
		}
		maprep[key] = value;
		refreshMap();
		outLog("set "+key+" map to "+value);
		return true;
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


void calc::delMap(string key) {
	try {
		maprep.erase(key);
		refreshMap();
		outLog("delete key " + key);
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}


void calc::inMapFromFile(string fileName,bool cover) {
	try {
		FILE *p = NULL;
#ifdef _MSC_VER
		fopen_s(&p,fileName.c_str(),"r");
#else
		p=fopen(fileName.c_str(),"r");
#endif
		if (!p) {
			throw sfError(ISTREAM_ERROR, "istream error");
		}
		mapStruct temp;
		int size;
		vector<mapStruct> data;
		fread(&size, sizeof(int), 1, p);
		for (int i = 0; i < size; ++i) {
			fread(&temp, sizeof(mapStruct), 1, p);
			if (strcmp(temp.sure, "SFCALC") != 0) {
				fclose(p);
				throw sfError(FILE_ERROR,"file error");
			}
			data.push_back(temp);
		}
		fclose(p);
		if(cover)  
		{
			maprep.clear();
		}
		for (vector<mapStruct>::iterator q = data.begin(); q != data.end(); ++q) {
			maprep[string(q->key)] = q->value;
		}
		refreshMap();
		convstr = "read map from file";
		outLog("read map from file");
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR,"other error");
	}
}


void calc::outMapToFile(string fileName)  {
	try {
		FILE *p = NULL;
#ifdef _MSC_VER
		fopen_s(&p, fileName.c_str(), "w");
#else
		p = fopen(fileName.c_str(), "w");
#endif
		if (!p) {
			throw sfError(OSTREAM_ERROR, "ostream error");
		}
		mapStruct temp;
		int size=maprep.size();
		vector<mapStruct> data;
		for (map<string, string>::iterator q = maprep.begin(); q != maprep.end();++q) {
#ifdef _MSC_VER
			strcpy_s(temp.sure,"SFCALC");
			strcpy_s(temp.key, q->first.c_str());
			strcpy_s(temp.value, q->second.c_str());
#else
			strcpy(temp.sure, "SFCALC");
			strcpy(temp.key, q->first.c_str());
			strcpy(temp.value, q->second.c_str());
#endif
			data.push_back(temp);
		}
		fwrite(&size, sizeof(int), 1, p);
		for (vector<mapStruct>::iterator q = data.begin(); q != data.end();++q) {
			fwrite(&*q, sizeof(mapStruct), 1, p);
		}
		fclose(p);
		
		convstr = "write map to file";
		outLog("write map to file");
	} catch (sfError &err) {
		outLog(err.output_str());
		throw;
	} catch (...) {
		throw sfError(OTHER_ERROR, "other error");
	}
}
